package cn.tx.dao.impl;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import cn.tx.dao.BaseDao;
import cn.tx.util.ERPConstants;
import cn.tx.util.Page;

public abstract class BaseDaoImpl<T, Q> extends HibernateDaoSupport implements BaseDao<T, Q> {

	@Override
	public void save(T t) {
		this.getHibernateTemplate().save(t);
	}

	@Override
	public void update(T t) {
		this.getHibernateTemplate().update(t);
	}

	@Override
	public void delete(T t) {
		this.getHibernateTemplate().delete(t);
	}

	@Override
	public T getObjectById(Object objId) {
		//获得指定的一个dao的model泛型的类对象
		Class clazz = this.getModelGenericClass();
		return (T) this.getHibernateTemplate().get(clazz, (Serializable) objId);
	}

	@Override
	public List<T> listAll() {
		//获得指定的一个dao的model泛型的类对象
		Class clazz = this.getModelGenericClass();
		List<T> find = this.getHibernateTemplate().find("from "+clazz.getName());
		
		return find;
	}

	@Override
	public List<T> selectObjByCondition(final Q q, final List<String> exclude) {
		//创建hql
		//String hql = "select u from "
		final String hql = this.createHql(q);
		System.out.println(hql);
		@SuppressWarnings("unchecked")
		List<T> list = this.getHibernateTemplate().executeFind(new HibernateCallback<List<T>>() {

			@Override
			public List<T> doInHibernate(Session session) throws HibernateException,
					SQLException {
				//创建查询对象
				Query query = session.createQuery(hql);
				//动态设置参数
				setDynamicParam(query, q, exclude);
				return query.list();
			}
		});
		
		
		return list;
	}
	
	public List<T> selectObjByConditionPage(final Q q, final int startNum, final List<String> exclude){
		//创建hql
		//String hql = "select u from "
		final String hql = this.createHql(q);
		System.out.println(hql);
		@SuppressWarnings("unchecked")
		List<T> list = this.getHibernateTemplate().executeFind(new HibernateCallback<List<T>>() {

			@Override
			public List<T> doInHibernate(Session session) throws HibernateException,
					SQLException {
				//创建查询对象
				Query query = session.createQuery(hql);
				//动态设置参数
				setDynamicParam(query, q, exclude);
				return query.setFirstResult(startNum).setMaxResults(ERPConstants.PAGE_SIZE).list();
			}
		});
		
		
		return list;
	}

	@Override
	public Long selectObjByConditionCount(final Q q, final List<String> exclude) {
		//创建hql
		//String hql = "select u from "
		final String hql = this.createHqlCount(q);
		System.out.println(hql);
		Long count = this.getHibernateTemplate().execute(new HibernateCallback<Long>() {

			@Override
			public Long doInHibernate(Session session) throws HibernateException,
					SQLException {
				//创建查询对象
				Query query = session.createQuery(hql);
				//动态设置参数
				setDynamicParam(query, q, exclude);
				
				return (Long) query.uniqueResult();
			}
		});
		
				
		return count;
	}
	
	/**
	 * 获得model的泛型的具体类
	 * @return
	 */
	public Class getModelGenericClass(){
		//获得当前的类的父类泛型类型
		Type genericSuperclass = this.getClass().getGenericSuperclass();
		//获得当前的类的父类泛型参数类型
		ParameterizedType pt = (ParameterizedType) genericSuperclass;
		//获得泛型数组
		Type[] types = pt.getActualTypeArguments();
		Class clazz = (Class) types[0];
		return clazz;
	}
	
	/**
	 * 创建hql
	 * @param q
	 * @return
	 */
	public abstract String createHql(Q q);
	
	public abstract String createHqlCount(Q q);
	
	
	public abstract String createConditionHql(Q q);
	
	
	/**
	 * 动态设置参数
	 * @param q
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	private final void setDynamicParam(Query query,Q q) {
		//获得查询对象的类对象
		Class<? extends Object> class1 = q.getClass();
		//获得子类的查询对象的属性
		Field[] fields = class1.getDeclaredFields();
		//获得当前查询对象的父类的属性
		Field[] pfields = class1.getSuperclass().getDeclaredFields();
		//从数组中转换的集合的长度不能变化
		List<Field> list1 = Arrays.asList(fields);
		List<Field> list2 = Arrays.asList(pfields);
		//定义一个大的集合
		List<Field> flist = new ArrayList<Field>();
		flist.addAll(list1);
		flist.addAll(list2);
		//便利这个集合
		for(Field field : flist){
			//获得属性的name
			String name = field.getName();
			//开启访问私有属性
			field.setAccessible(true);
			//获得这个属性的值
			Object object = null;
			try {
				object = field.get(q);
			} catch (IllegalArgumentException | IllegalAccessException e) {
				e.printStackTrace();
			}
			//获得属性的类型
			Class<?> type = field.getType();
			if(object != null && !StringUtils.equals(name, "pageNo") ){
				//字符串模糊查询
				if(type == String.class){
					String str = (String) object;
					if(!"".equals(str))
					query.setParameter(name, "%"+object+"%");
				}else if(type.isArray()){
					query.setParameterList(name, (Collection)object);
				}else{
					query.setParameter(name, object);
				}
				//
			}
			
			
		}
		
	}
	/**
	 * 
	 * @param query
	 * @param q
	 * @param exclude:pageNo,empId
	 */
	private final void setDynamicParam(Query query,Q q, List<String> exclude) {
		//获得查询对象的类对象
		Class<? extends Object> class1 = q.getClass();
		//获得子类的查询对象的属性
		Field[] fields = class1.getDeclaredFields();
		//获得当前查询对象的父类的属性
		Field[] pfields = class1.getSuperclass().getDeclaredFields();
		//从数组中转换的集合的长度不能变化
		List<Field> list1 = Arrays.asList(fields);
		List<Field> list2 = Arrays.asList(pfields);
		//定义一个大的集合
		List<Field> flist = new ArrayList<Field>();
		flist.addAll(list1);
		flist.addAll(list2);
		//便利这个集合
		for(Field field : flist){
			//获得属性的name
			String name = field.getName();
			//判断是否有排除属性
			if(exclude != null && exclude.contains(name)){
				continue;
			}
			//开启访问私有属性
			field.setAccessible(true);
			//获得这个属性的值
			Object object = null;
			try {
				object = field.get(q);
			} catch (IllegalArgumentException | IllegalAccessException e) {
				e.printStackTrace();
			}
			//获得属性的类型
			Class<?> type = field.getType();
			if(object != null){
				//字符串模糊查询
				if(type == String.class){
					String str = (String) object;
					if(!"".equals(str))
						query.setParameter(name, "%"+object+"%");
				}else if(type == List.class){
					query.setParameterList(name, (Collection) object);
				}else{
					query.setParameter(name, object);
				}
				//
			}
			
			
		}
		
	}

}
